package com.example.demofx.master;

import com.opencsv.CSVParserBuilder;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.CSVWriter;
import javafx.scene.control.Alert;
import javafx.scene.control.ChoiceDialog;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.*;
import java.time.LocalDate;
import java.util.*;

import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.QuotedPrintableCodec;

public class ContactFileManager {
    private final ContactManager contactManager;
    private final ContactSavedListener contactSavedListener;
    private final GroupChangedListener groupChangedListener;
    private final SidebarCreator sidebarCreator;
    private final TableAndPaginationCreator tableAndPaginationCreator;
    private final String DB_URL = "jdbc:sqlite:" + System.getProperty("user.dir") + "/identifier.sqlite";

    public ContactFileManager(ContactManager contactManager,
                              ContactSavedListener contactSavedListener,
                              GroupChangedListener groupChangedListener,
                              SidebarCreator sidebarCreator,
                              TableAndPaginationCreator tableAndPaginationCreator) {
        this.contactManager = contactManager;
        this.contactSavedListener = contactSavedListener;
        this.groupChangedListener = groupChangedListener;
        this.sidebarCreator = sidebarCreator;
        this.tableAndPaginationCreator = tableAndPaginationCreator;
    }

    // csv导入
    public void importCSV(File file) throws IOException {
        // 定义必填列
        List<String> requiredHeaders = Arrays.asList("name", "mobile");
        int totalRows = 0;  // 记录总行数
        int successRows = 0;  // 记录成功导入的行数
        int failedRows = 0;  // 记录导入失败的行数
        //  确保资源自动关闭
        try (CSVReader reader = new CSVReaderBuilder(
                new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))
                .withCSVParser(new CSVParserBuilder()
                        .withSeparator(',')  // 逗号分隔符
                        .withQuoteChar('"')  // 双引号引用字符
                        .build())
                .build()) {
            String[] headerArray = reader.readNext();  // 读取CSV文件的第一行作为表头
            if (headerArray == null) {
                throw new IllegalArgumentException("CSV 文件为空，不包含表头");
            }
            // 检查必填列是否存在
            Set<String> missingHeaders = new HashSet<>();
            for (String header : requiredHeaders) {
                if (!Arrays.asList(headerArray).contains(header)) {
                    missingHeaders.add(header);
                }
            }
            if (!missingHeaders.isEmpty()) {  // 如果有缺失的必填列，抛出异常
                throw new IllegalArgumentException("CSV 文件缺少必填列：" + missingHeaders);
            }
            // 获取表头索引映射
            Map<String, Integer> headerIndexMap = new HashMap<>();
            for (int i = 0; i < headerArray.length; i++) {
                headerIndexMap.put(headerArray[i], i);
            }
            String[] line;
            // 逐行读取CSV文件
            while ((line = reader.readNext()) != null) {
                totalRows++;
                try {
                    // 跳过空行或无效行
                    if (line.length < 2 || line[0].trim().isEmpty() || line[1].trim().isEmpty()) {
                        System.out.println("警告：跳过第 " + totalRows + " 行：姓名或手机号为空");
                        failedRows++;
                        continue;
                    }
                    Contact contact = new Contact();
                    // 根据表头映射设置必填字段
                    if (headerIndexMap.containsKey("name") && headerIndexMap.get("name") < line.length) {
                        contact.setName(line[headerIndexMap.get("name")].trim());
                    }
                    if (headerIndexMap.containsKey("mobile") && headerIndexMap.get("mobile") < line.length) {
                        contact.setMobile(line[headerIndexMap.get("mobile")].trim());
                    }
                    // 根据表头映射其他字段
                    for (String key : headerIndexMap.keySet()) {
                        int index = headerIndexMap.get(key);
                        // 打印 line 数组长度和 index 的值
                        System.out.println("当前行: " + totalRows + ", line 数组长度: " + line.length + ", 尝试访问的索引: " + index);
                        if (index >= line.length) {
                            System.out.println("警告：第 " + totalRows + " 行缺少字段 '" + key + "'，跳过该字段");
                            continue;
                        }
                        String value = line[index] != null ? line[index].trim() : "";
                        if (value.isEmpty()) continue; // 跳过空值
                        try {
                            switch (key) {
                                case "birthday":
                                    contact.setBirthday(LocalDate.parse(value));
                                    break;
                                case "starred":
                                    contact.setStarred(
                                            "1".equalsIgnoreCase(value) ||
                                                    "true".equalsIgnoreCase(value) ||
                                                    "是".equalsIgnoreCase(value)
                                    );
                                    break;
                                case "phone": contact.setPhone(value); break;
                                case "email": contact.setEmail(value); break;
                                case "company": contact.setCompany(value); break;
                                case "homeAddress": contact.setHomeAddress(value); break;
                                case "postalCode": contact.setPostalCode(value); break;
                                case "remark": contact.setRemark(value); break;
                                case "wechat": contact.setWechat(value); break;
                                case "QQ": contact.setQQ(value); break;
                                case "photo_path": contact.setPhotoPath(value); break;
                            }
                        } catch (NumberFormatException e) {
                            System.err.println("错误：第 " + totalRows + " 行格式错误：字段 '" + key + "' 的值 '" + value + "' 不是有效数字");
                        } catch (Exception e) {
                            System.err.println("错误：第 " + totalRows + " 行处理失败：字段 '" + key + "' 的值 '" + value + "' 格式错误：" + e.getMessage());
                        }
                    }
                    // 最终验证（确保必填字段未被清空）
                    if (contact.getName() == null || contact.getMobile() == null) {
                        System.out.println("警告：跳过第 " + totalRows + " 行：处理后姓名或手机号为空");
                        failedRows++;
                        continue;
                    }
                    // 插入数据库
                    contactManager.addContact(contact);
                    successRows++;
                } catch (Exception e) {
                    System.err.println("错误：处理第 " + totalRows + " 行时发生未知异常：" + e.getMessage());
                    e.printStackTrace(); // 打印异常堆栈信息
                    failedRows++;
                }
            }
            System.out.println("CSV 导入完成：共 " + totalRows + " 行，成功 " + successRows + " 行，失败 " + failedRows + " 行");
            contactSavedListener.onContactSaved(); // 通知导入完成
        } catch (FileNotFoundException e) {
            throw new IOException("指定的 CSV 文件不存在：" + file.getAbsolutePath(), e);
        } catch (UnsupportedEncodingException e) {
            throw new IOException("CSV 文件编码不支持", e);
        } catch (IOException e) {
            throw new IOException("读取 CSV 文件时发生 I/O 错误：" + e.getMessage(), e);
        } catch (Exception e) {
            throw new IOException("CSV 导入失败：" + e.getMessage(), e);
        }
    }

    // CSV导出
    public void exportToCSV(List<Contact> contacts, File file) throws Exception {
        try (CSVWriter writer = new CSVWriter(new FileWriter(file))) {
            // 写入表头（按 Contact 类的属性顺序）
            String[] header = {
                    "id", "name", "mobile", "phone", "email", "company", "homeAddress", "postalCode",
                    "remark", "birthday", "starred", "wechat", "QQ", "photo_path"
            };
            writer.writeNext(header);

            for (Contact contact : contacts) {
                String[] row = {
                        String.valueOf(contact.getId()),
                        contact.getName(),
                        contact.getMobile(),
                        contact.getPhone(),
                        contact.getEmail(),
                        contact.getCompany(),
                        contact.getHomeAddress(),
                        contact.getPostalCode(),
                        contact.getRemark(),
                        contact.getBirthday() != null ? contact.getBirthday().toString() : "",
                        contact.isStarred() ? "1" : "0",
                        contact.getWechat(),
                        contact.getQQ(),
                        contact.getPhotoPath()
                };
                writer.writeNext(row);
            }
            showAlert("成功", "导出CSV文件成功！");
        }
    }

    // 导出vCard
    public void exportToVCard(List<Contact> contacts, File file) throws IOException {
        String projectPath = System.getProperty("user.dir");
        QuotedPrintableCodec codec = new QuotedPrintableCodec("UTF-8");//处理特殊字符

        try (BufferedWriter writer = new BufferedWriter(  //自动关闭资源
                new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) {
            for (Contact contact : contacts) { // 遍历联系人列表，逐个导出
                writer.write("BEGIN:VCARD\n");
                writer.write("VERSION:3.0\n");
                // 姓名  使用QuotedPrintable编码处理特殊字符
                if (contact.getName() != null) {
                    String encodedName = codec.encode(contact.getName());
                    writer.write("FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:" + encodedName + "\n");
                }
                // 电话
                if (contact.getMobile() != null) {
                    writer.write("TEL;TYPE=CELL:" + contact.getMobile() + "\n");
                }
                if (contact.getPhone() != null) {
                    writer.write("TEL;TYPE=WORK:" + contact.getPhone() + "\n");
                }
                // 邮箱
                if (contact.getEmail() != null) {
                    writer.write("EMAIL:" + contact.getEmail() + "\n");
                }
                // 公司，使用QuotedPrintable编码
                if (contact.getCompany() != null) {
                    String encodedOrg = codec.encode(contact.getCompany());
                    writer.write("ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:" + encodedOrg + "\n");
                }
                // 地址与邮政编码
                String address = contact.getHomeAddress() != null ? codec.encode(contact.getHomeAddress()) : "";
                String postal = contact.getPostalCode() != null ? contact.getPostalCode() : "";
                // ADR 格式: PO Box;扩展地址;街道;城市;省份;邮编;国家
                writer.write("ADR;TYPE=HOME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;" + address + ";;;;" + postal + ";\n");
                // 生日
                if (contact.getBirthday() != null) {
                    writer.write("BDAY:" + contact.getBirthday() + "\n");
                }
                // qq微信
                if (contact.getWechat() != null) {
                    writer.write("X-WECHAT:" + contact.getWechat() + "\n");
                }
                if (contact.getQQ() != null) {
                    writer.write("X-QQ:" + contact.getQQ() + "\n");
                }
                // 备注,使用QuotedPrintable编码
                if (contact.getRemark()!= null) {
                    String encodedRemark = codec.encode(contact.getRemark());
                    writer.write("NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:" + encodedRemark + "\n");
                }
                // 图片
                if (contact.getPhotoPath() != null) {
                    File imageFile = new File(projectPath, File.separator + "images" + File.separator + contact.getPhotoPath());
                    try (FileInputStream fis = new FileInputStream(imageFile);
                         ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                        byte[] buffer = new byte[1024]; // 读取图片内容到字节数组
                        int bytesRead;
                        while ((bytesRead = fis.read(buffer)) != -1) {
                            bos.write(buffer, 0, bytesRead);
                        }
                        byte[] photoBytes = bos.toByteArray();
                        String base64Photo = Base64.getEncoder().encodeToString(photoBytes);// 对图片内容进行Base64编码
                        String mimeType = detectImageMimeType(photoBytes);// 检测图片MIME类型
                        String type = mimeType.equals("image/png") ? "PNG" : "JPEG";// 根据MIME类型确定图片格式
                        // 将Base64编码的图片内容写入vCard文件，每75个字符换行
                        writer.write("PHOTO;ENCODING=b;TYPE=" + type + ":" + wrapBase64(base64Photo) + "\n");
                    } catch (IOException e) {
                        System.err.println("读取图片失败: " + e.getMessage());
                    }
                }
                writer.write("END:VCARD\n\n");
            }
            showAlert("成功", "导出vCard文件成功！");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Base64 换行：每 75 个字符换行，续行前加空格
    private String wrapBase64(String base64) {
        StringBuilder result = new StringBuilder();
        int index = 0;
        while (index < base64.length()) {
            int end = Math.min(index + 75, base64.length());
            if (index > 0) {
                result.append("\n ");
            }
            result.append(base64, index, end);
            index = end;
        }
        return result.toString();
    }

    // 检测图片MIME类型的辅助方法
    private String detectImageMimeType(byte[] imageBytes) {
        // 检查文件头来确定图片类型
        if (imageBytes.length >= 8 &&
                (imageBytes[0] & 0xFF) == 0x89 &&
                (imageBytes[1] & 0xFF) == 0x50 &&
                (imageBytes[2] & 0xFF) == 0x4E &&
                (imageBytes[3] & 0xFF) == 0x47 &&
                (imageBytes[4] & 0xFF) == 0x0D &&
                (imageBytes[5] & 0xFF) == 0x0A &&
                (imageBytes[6] & 0xFF) == 0x1A &&
                (imageBytes[7] & 0xFF) == 0x0A) {
            return "image/png";
        } else if (imageBytes.length >= 2 &&
                (imageBytes[0] & 0xFF) == 0xFF &&
                (imageBytes[1] & 0xFF) == 0xD8) {
            return "image/jpeg";
        } else {
            // 默认返回PNG（可根据需要修改）
            return "image/png";
        }
    }

    // 导入vcard
    public void importVCard(File file) throws Exception {
        QuotedPrintableCodec codec = new QuotedPrintableCodec("UTF-8");  // 创建QuotedPrintable解码器解析特殊字符
        String projectPath = System.getProperty("user.dir");
        String imageDirPath = projectPath + File.separator + "images"; // 图片保存目录

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
            String line;
            Contact contact = null;  // 当前正在处理的联系人
            StringBuilder photoData = null;  // 存储照片的Base64编码数据
            String photoMimeType = null;  // 照片的MIME类型

            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.isEmpty()) continue;

                if (line.startsWith("BEGIN:VCARD")) {// 开始处理
                    contact = new Contact();
                    photoData = new StringBuilder();
                } else if (line.startsWith("END:VCARD")) {// 结束处理
                    // 处理照片数据
                    if (photoData != null && photoData.length() > 0) {
                        byte[] bytes = Base64.getDecoder().decode(photoData.toString());
                        String ext = detectFileExtension(bytes);
                        String filename = UUID.randomUUID().toString() + "." + ext;
                        String fullPath = imageDirPath + File.separator + filename;
                        Files.write(Paths.get(fullPath), bytes);
                        contact.setPhotoPath(filename);
                    }
                    // 存入数据库
                    saveContactToDatabase(contact);
                    contact = null;
                } else if (contact != null) {
                    // 处理PHOTO字段
                    if (line.startsWith("PHOTO")) {
                        int idx = line.indexOf(":");
                        photoMimeType = line.contains("PNG") ? "image/png" : "image/jpeg";
                        photoData = new StringBuilder(line.substring(idx + 1));
                        // 读取可能的续行
                        while (true) {
                            reader.mark(1024); // 设置 mark：必须在 readLine() 之前
                            String nextLine = reader.readLine();
                            if (nextLine == null || !nextLine.startsWith(" ")) {
                                reader.reset(); // 回退到 mark 的位置
                                break;
                            }
                            photoData.append(nextLine.trim());
                        }
                        continue;
                    }
                    // 常规字段解析
                    if (line.startsWith("FN")) {
                        contact.setName(parseField(line, "FN", codec));
                    } else if (line.startsWith("TEL")) {
                        String val = line.substring(line.indexOf(":") + 1);
                        if (line.contains("CELL")) {
                            contact.setMobile(val);
                        } else {
                            contact.setPhone(val);
                        }
                    } else if (line.startsWith("EMAIL")) {
                        contact.setEmail(line.substring(line.indexOf(":") + 1));
                    } else if (line.startsWith("ORG")) {
                        contact.setCompany(parseField(line, "ORG", codec));
                    } else if (line.startsWith("BDAY")) {
                        contact.setBirthday(LocalDate.parse(line.substring(line.indexOf(":") + 1)));
                    } else if (line.startsWith("X-WECHAT")) {
                        contact.setWechat(line.substring(line.indexOf(":") + 1));
                    } else if (line.startsWith("X-QQ")) {
                        contact.setQQ(line.substring(line.indexOf(":") + 1));
                    }
                    else if (line.startsWith("ADR")) {
                        String addrValue = parseField(line, "ADR", codec);
                        // 拆分7段地址
                        String[] parts = addrValue.split(";", -1); // 保留空字段
                        if (parts.length >= 7) {
                            contact.setHomeAddress(parts[2]);  // 第三个字段是街道
                            contact.setPostalCode(parts[6]);   // 第六个字段是邮编
                        }
                    } else if (line.startsWith("NOTE")) {
                        contact.setRemark(parseField(line, "NOTE", codec));
                    }
                }
            }
            // 导入完成后刷新UI
            contactSavedListener.onContactSaved();
        }
    }

    // 解码 QP 字段的通用方法
    private String parseField(String line, String key, QuotedPrintableCodec codec) throws Exception {
        int index = line.indexOf(":");
        String value = line.substring(index + 1);
        if (line.contains("ENCODING=QUOTED-PRINTABLE")) {
            return codec.decode(value);
        } else {
            return value;
        }
    }


    private void saveContactToDatabase(Contact contact) {
        String insertQuery = "INSERT INTO contacts (name, phone, mobile, email, birthday, " +
                "company, address, postal_code, im_WeChat, im_QQ, photo, photo_path, starred, notes) " +
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

        try (Connection conn = DriverManager.getConnection(DB_URL);
             PreparedStatement pstmt = conn.prepareStatement(insertQuery)) {

            pstmt.setString(1, contact.getName());
            pstmt.setString(2, contact.getPhone());
            pstmt.setString(3, contact.getMobile());
            pstmt.setString(4, contact.getEmail());

            // 生日处理
            if (contact.getBirthday() != null) {
                pstmt.setString(5, contact.getBirthday().toString());
            } else {
                pstmt.setNull(5, Types.VARCHAR);
            }

            pstmt.setString(6, contact.getCompany());
            pstmt.setString(7, contact.getHomeAddress());
            pstmt.setString(8, contact.getPostalCode());
            pstmt.setString(9, contact.getWechat());
            pstmt.setString(10, contact.getQQ());

            // 图片二进制数据处理（如果需要存入数据库）
            if (contact.getPhotoPath() != null) {
                File photoFile = new File(contact.getPhotoPath());
                if (photoFile.exists()) {
                    byte[] photoBytes = Files.readAllBytes(photoFile.toPath());
                    pstmt.setBytes(11, photoBytes);
                } else {
                    pstmt.setNull(11, Types.BLOB);
                }
            } else {
                pstmt.setNull(11, Types.BLOB);
            }

            pstmt.setString(12, contact.getPhotoPath());
            pstmt.setInt(13, contact.isStarred() ? 1 : 0);
            pstmt.setString(14, contact.getRemark());

            pstmt.executeUpdate();
        } catch (SQLException | IOException e) {
            System.err.println("保存联系人到数据库失败: " + e.getMessage());
        }
    }


    // 根据MIME类型获取文件扩展名
    private String getFileExtensionFromMimeType(String mimeType) {
        if (mimeType == null) return "png"; // 默认使用PNG

        switch (mimeType.toLowerCase()) {
            case "image/png":
                return "png";
            case "image/jpeg":
            case "image/jpg":
                return "jpg";
            case "image/gif":
                return "gif";
            case "image/webp":
                return "webp";
            default:
                return "png"; // 未知类型默认使用PNG
        }
    }

    // 根据文件头检测文件扩展名
    private String detectFileExtension(byte[] bytes) {
        if (bytes.length >= 8 &&
                (bytes[0] & 0xFF) == 0x89 &&
                (bytes[1] & 0xFF) == 0x50 &&
                (bytes[2] & 0xFF) == 0x4E &&
                (bytes[3] & 0xFF) == 0x47 &&
                (bytes[4] & 0xFF) == 0x0D &&
                (bytes[5] & 0xFF) == 0x0A &&
                (bytes[6] & 0xFF) == 0x1A &&
                (bytes[7] & 0xFF) == 0x0A) {
            return "png";
        } else if (bytes.length >= 2 &&
                (bytes[0] & 0xFF) == 0xFF &&
                (bytes[1] & 0xFF) == 0xD8) {
            return "jpg";
        } else if (bytes.length >= 6 &&
                ((bytes[0] & 0xFF) == 0x47 && (bytes[1] & 0xFF) == 0x49 &&
                        (bytes[2] & 0xFF) == 0x46 && (bytes[3] & 0xFF) == 0x38 &&
                        ((bytes[4] & 0xFF) == 0x37 || (bytes[4] & 0xFF) == 0x39) &&
                        (bytes[5] & 0xFF) == 0x61)) {
            return "gif";
        } else if (bytes.length >= 12 &&
                (bytes[0] & 0xFF) == 0x52 && (bytes[1] & 0xFF) == 0x49 &&
                (bytes[2] & 0xFF) == 0x46 && (bytes[3] & 0xFF) == 0x46 &&
                (bytes[8] & 0xFF) == 0x57 && (bytes[9] & 0xFF) == 0x45 &&
                (bytes[10] & 0xFF) == 0x42 && (bytes[11] & 0xFF) == 0x50) {
            return "webp";
        } else {
            return "png"; // 无法识别时默认使用PNG
        }
    }
    // 显示提示对话框
    private void showAlert(String title, String content) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle(title);
        alert.setHeaderText(null);
        alert.setContentText(content);
        alert.showAndWait();
    }

    // 处理导入按钮点击事件
    public void handleImportButtonClick(Stage stage) {
        // 创建格式选择对话框
        ChoiceDialog<String> formatDialog = new ChoiceDialog<>("CSV", "CSV", "vCard");
        formatDialog.setTitle("导入联系人");
        formatDialog.setHeaderText("选择导入格式");
        formatDialog.setContentText("请选择要导入的文件格式：");

        formatDialog.showAndWait().ifPresent(format -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("选择文件");

            if ("CSV".equals(format)) {
                fileChooser.getExtensionFilters().add(
                        new FileChooser.ExtensionFilter("CSV files (*.csv)", "*.csv")
                );
            } else {
                fileChooser.getExtensionFilters().add(
                        new FileChooser.ExtensionFilter("vCard files (*.vcf, *.vcx)", "*.vcf;*.vcx")
                );
            }

            File selectedFile = fileChooser.showOpenDialog(stage);
            if (selectedFile != null) {
                try {
                    if ("CSV".equals(format)) {
                        importCSV(selectedFile); // 使用现有的CSV导入方法
                    } else {
                        importVCard(selectedFile); // 新增vCard导入方法
                    }
                } catch (Exception ex) {
                    showAlert("错误", "导入文件时出错：" + ex.getMessage());
                }
            }
        });
    }

    // 处理导出按钮点击事件
    public void handleExportButtonClick(Stage stage, List<Contact> selectedContacts) {
        if (selectedContacts.isEmpty()) {
            showAlert("提示", "请至少选择一个联系人导出！");
            return;
        }

        // 创建格式选择对话框
        ChoiceDialog<String> dialog = new ChoiceDialog<>("CSV", "CSV", "vCard");
        dialog.setTitle("导出联系人");
        dialog.setHeaderText("选择导出格式");
        dialog.setContentText("请选择导出文件的格式：");

        dialog.showAndWait().ifPresent(format -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("保存文件");

            if ("CSV".equals(format)) {
                fileChooser.getExtensionFilters().add(
                        new FileChooser.ExtensionFilter("CSV files (*.csv)", "*.csv")
                );
            } else {
                fileChooser.getExtensionFilters().add(
                        new FileChooser.ExtensionFilter("vCard files (*.vcf)", "*.vcf")
                );
            }

            File selectedFile = fileChooser.showSaveDialog(stage);
            if (selectedFile != null) {
                try {
                    if ("CSV".equals(format)) {
                        exportToCSV(selectedContacts, selectedFile);
                    } else {
                        exportToVCard(selectedContacts, selectedFile); // 直接导出vCard
                    }
                } catch (Exception ex) {
                    showAlert("错误", "导出文件时出错：" + ex.getMessage());
                }
            }
        });
    }
}